package ca.uvic.cs.cogz.reports;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import ca.uvic.cs.cogz.mapping.core.AbstractMapElement;
import ca.uvic.cs.cogz.mapping.core.MappingCollection;
import ca.uvic.cs.cogz.mapping.core.MappingTypeManager.MappingType;
import ca.uvic.cs.cogz.mapping.ontology.DataLoaderFacade;

public class MappingStatusReport extends AbstractReport {
	private int tableNumber = 1;

	public Document getReportAsXML() {
		tableNumber = 1;
		String reportXml = generateReport();

		DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder domBuilder = domFactory.newDocumentBuilder();
			InputSource source = new InputSource(new StringReader(reportXml));

			return domBuilder.parse(source);

			//OutputFormat format = new OutputFormat(doc);
			//format.setLineWidth(80);
			//format.setIndenting(true);
			//format.setIndent(2);

			//XMLSerializer serializer = new XMLSerializer(System.out, format);
			//serializer.serialize(doc);
		} catch (Exception e) {
			//  Auto-generated catch block
			e.printStackTrace();
		}

		return null;
	}

	public String getReportAsHTML() {
		tableNumber = 1;
		//Document doc = getReportAsXML();
		StringBuilder reportHTML = new StringBuilder();
		reportHTML.append(getHTMLStart());

		reportHTML.append(getReportSummaryAsHTML());
		reportHTML.append(getReportContentsAsHTML());

		reportHTML.append(getHTMLEnd());

		return reportHTML.toString();
	}

	public String getReportTitle() {
		return "Mapping Status Report";
	}

	private String generateReport() {
		StringBuilder report = new StringBuilder();

		report.append("<Report>");
		report.append(getReportSummary());
		report.append(getReportContents());
		report.append("</Report>");

		return report.toString();
	}

	private String getReportContents() {
		StringBuilder report = new StringBuilder();

		report.append("<ReportContents>");
		report.append(getMappingSummary(MappingType.CANDIDATE_MAPPING));
		report.append("</ReportContents>");

		return report.toString();
	}

	private String getMappingSummary(MappingType mappingType) {
		MappingCollection mappingCollection = DataLoaderFacade.getInstance().getMappingCollection();
		StringBuilder report = new StringBuilder();

		Set<String> seen = new HashSet<String>();
		report.append("<Mappings type=\"" + mappingType.toString() + "\">");
		for (AbstractMapElement mapElement : mappingCollection.getMappedElements(mappingType)) {
			if (!seen.contains(mapElement.toString())) {
				report.append("<Mapping>");
				report.append("<Source>" + mapElement.getSourceFrame().getBrowserText() + "</Source>");
				report.append("<Target>" + mapElement.getTargetFrame().getBrowserText() + "</Target>");
				report.append("<Annnotation><![CDATA[" + mapElement.getAnnotation() + "]]></Annnotation>");
				report.append("</Mapping>");

				seen.add(mapElement.toString());
			}
		}
		report.append("</Mappings>");

		return report.toString();
	}

	private String getReportContentsAsHTML() {
		StringBuilder report = new StringBuilder();

		report.append(getMappingSummaryAsHTML(MappingType.CANDIDATE_MAPPING));
		report.append(getMappingSummaryAsHTML(MappingType.VERIFIED_MAPPING));

		return report.toString();
	}

	private String getMappingSummaryAsHTML(MappingType mappingType) {
		MappingCollection mappingCollection = DataLoaderFacade.getInstance().getMappingCollection();
		StringBuilder report = new StringBuilder();

		ArrayList<AbstractMapElement> mappingElements = mappingCollection.getMappedElements(mappingType);
		if (mappingElements.size() != 0) {
			report.append("<table id=\"mytable\" cellspacing=\"0\">");
			report.append("<caption>Table " + (tableNumber++) + ": " + mappingType.toString() + "s</caption>");
			report.append("<tr>");
			report.append("<th scope=\"col\" class=\"spec\">Source term</th>");
			report.append("<th scope=\"col\">Target term</th>");
			report.append("<th scope=\"col\">Reason</th>");
			report.append("</tr>");

			Set<String> seen = new HashSet<String>();
			for (AbstractMapElement mapElement : mappingElements) {
				if (!seen.contains(mapElement.toString())) {
					report.append("<tr>");
					report.append("<td class=\"spec\">" + mapElement.getSourceFrame().getBrowserText() + "</td>");
					report.append("<td>" + mapElement.getTargetFrame().getBrowserText() + "</td>");
					report.append("<td>" + mapElement.getAnnotation() + "</td>");
					report.append("</tr>");
					seen.add(mapElement.toString());
				}
			}
			report.append("</table>");
		}

		return report.toString();
	}
}
